import { DefaultStage } from "../default-stage";
import { RawAssetsName, RawAssetsUrl } from "../../raw-assets-info";
import { GradientSkybox } from 'babylon-lib/preset/gradient-skybox';
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";
import { Drag } from 'babylon-lib/drag/drag';
import { DragCommonConfig } from 'babylon-lib/drag/config/drag-common-config';
import { DragNoneLimit } from 'babylon-lib/drag/limit/drag-none-limit';
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import { Color3 } from "@babylonjs/core/Maths/math.color";
import { Debug } from "babylon-lib/gui/control/debug";
import { Vector3 } from "@babylonjs/core/Maths/math";
import { Scene } from "@babylonjs/core/scene";
import { PBRMaterial } from "@babylonjs/core/Materials/PBR/pbrMaterial";
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
import { AnimationFrame } from 'babylon-lib/animation/animation-frame';
import '@babylonjs/core/Collisions/collisionCoordinator';
import { Helper } from "babylon-lib/tool/helper";
import { AbstractControl } from "babylon-lib/gui/control/abstract-control";
import { GravityRoaming } from "babylon-lib/preset/gravity-roaming";
import { PointingLabel } from 'babylon-lib/preset/pointing-label';
import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { HardLineGeometry } from "babylon-lib/geometry/hard-line-geometry";
import { HardLineMaterial } from "babylon-lib/material/hard-line-material";
import { Mesh } from "@babylonjs/core/Meshes/mesh";
import { BasicLineGeometry } from 'babylon-lib/geometry/basic-line-geometry';
import { BasicLineMaterial } from 'babylon-lib/material/basic-line-material';
import { ShaderMaterial } from "@babylonjs/core/Materials/shaderMaterial";
import { DeviceInputPreset } from 'babylon-lib/preset/device-input/device-input-preset';
import { DeviceInputKey, InputStatus } from "babylon-lib/preset/device-input/device-information";
import { Utils } from "babylon-lib/index";
import { ControllerImage } from 'babylon-lib/texture/icon-image/controller-image';
import { ImmersiveImage } from "babylon-lib/texture/icon-image/immersive-image";
import { CreateUIButton } from "babylon-lib/gui/control/ui-button";


class GenerateComponent {
    public static initialize(stage: DefaultStage): void {
        this.setModel(stage);
        this.testDebug(stage);
        this.initializeSky(stage);
        // this.initializeLabel(stage);
        this.initializeMovement(stage);
        // this.testGLLine(stage.mainScene);
        this.testDeviceInput(stage);
        // this.testIcon(stage);
    }

    private static testIcon(stage: DefaultStage): void {
        const ct = ImmersiveImage(5, '#ffffff');

        const mesh = MeshBuilder.CreatePlane('hjsdfsd', { size: 1 }, stage.mainScene);
        const material = new StandardMaterial('jhsdfsd', stage.mainScene);
        material.disableLighting = true;
        material.emissiveTexture = new Texture(ct);
        mesh.material = material;
        mesh.billboardMode = TransformNode.BILLBOARDMODE_ALL;
        mesh.renderingGroupId = 2;
    }

    private static async testDeviceInput(stage: DefaultStage): Promise<void> {
        DeviceInputPreset.initialize(stage.mainScene);

        // DeviceInputPreset.onInput(()=>{console.log('mouseLeft')},InputStatus.click,DeviceInputKey.mouseLeft);
        // DeviceInputPreset.onInput(()=>{console.log('mouseMiddle')},InputStatus.click,DeviceInputKey.mouseMiddle);
        // DeviceInputPreset.onInput(()=>{console.log('mouseRight')},InputStatus.click,DeviceInputKey.mouseRight);
        // DeviceInputPreset.onInput((e)=>{Debug.log('click')},InputStatus.click,DeviceInputKey.pointer);
        DeviceInputPreset.onInput((e) => { Debug.log('press') }, InputStatus.press, DeviceInputKey.pointer);
        // DeviceInputPreset.onInput((e)=>{Debug.log('down')},InputStatus.down,DeviceInputKey.pointer);
        // DeviceInputPreset.onInput((e)=>{Debug.log('up')},InputStatus.up,DeviceInputKey.pointer);
        // DeviceInputPreset.onInput((e)=>{Debug.log('wheel')},InputStatus.wheel,DeviceInputKey.pointer);
        // DeviceInputPreset.onInput((e)=>{Debug.log('move')},InputStatus.move,DeviceInputKey.pointer);

        const sxr = !!navigator.xr;
        Debug.log('xr', sxr)
        if (sxr) navigator.xr?.isSessionSupported('immersive-vr').then((b) => { Debug.log('vr', b) })
        if (sxr) navigator.xr?.isSessionSupported('immersive-ar').then((b) => { Debug.log('ar', b) })
    }

    private static testGLLine(scene: Scene): void {

        let count = 0;
        setInterval(() => {
            if (count > 1000) return;
            const ps = [
                new Vector3(Math.random() * 10 - 5, Math.random() * 10 - 5, Math.random() * 10 - 5),
                new Vector3(Math.random() * 10 - 5, Math.random() * 10 - 5, Math.random() * 10 - 5),
            ];
            // const g=new BasicLineGeometry('dfsd'+count,ps,{
            //     autoUpdateDistances:true,
            // },scene);

            // const m=new Mesh('asdfs',scene);
            // g.applyToMesh(m);
            // m.material=new BasicLineMaterial('ffd'+count,scene,{
            //     color:new Color3(0,1,0),
            //     dashed:true,
            // });

            const l = MeshBuilder.CreateLines('sedfsdf' + count, { points: ps }, scene)

        }, 100);
    }

    private static initializeLabel(stage: DefaultStage): void {

        // const line=MeshBuilder.CreateLines('line',{
        //     points:[new Vector3(-5,0,0),new Vector3(5,0,0)],
        //     updatable:true
        // },stage.mainScene);
        // line.isVisible=false;
        for (let i = 0; i < 50; i++) {

            //34-35
            const lb = new PointingLabel('test' + i, {
                text: 'testLabel' + i,
                pointRadius: 0.03,
                fontSize: 24,
                background: '#002255',
                borderRadius: 5,
                border: '#ff00ff',
                vivid: 1,
                // useBasicLine:true,
                autoUpdatePointLineStart: true
            }, stage.mainScene);
            lb.position = new Vector3(Math.random() * 10 - 5, Math.random() * 5 - 2.5, Math.random() * 10 - 5);
            // 11-12
            lb.points = [new Vector3(Math.random() * 10 - 5, Math.random() * 5 - 2.5, Math.random() * 10 - 5)];
            // const line=MeshBuilder.CreateLines('line'+i,{
            //     points:[new Vector3(-5,0,0),new Vector3(5,0,0)],
            //     updatable:true,
            // },stage.mainScene);
            // const ps=[
            //     new Vector3(Math.random()*10-5,Math.random()*5-2.5,Math.random()*10-5),
            //     new Vector3(Math.random()*10-5,Math.random()*5-2.5,Math.random()*10-5),
            //     new Vector3(Math.random()*10-5,Math.random()*5-2.5,Math.random()*10-5),
            //     new Vector3(Math.random()*10-5,Math.random()*5-2.5,Math.random()*10-5),
            // ];
            // MeshBuilder.CreateLines('line'+i,{
            //     points:ps,
            //     instance:line,
            //     updatable:true,
            // },stage.mainScene);
            // setInterval(()=>{
            //     MeshBuilder.CreateLines('line'+i,{
            //         points:[new Vector3(Math.random()*10-5,Math.random()*5-2.5,Math.random()*10-5),
            //             new Vector3(Math.random()*10-5,Math.random()*5-2.5,Math.random()*10-5),],
            //         instance:line,
            //         updatable:true,
            //     },stage.mainScene);
            // },16);
        }
    }

    private static initializeMovement(stage: DefaultStage): void {
        const scene = stage.mainScene;
        Helper.setSceneMesh(scene, 'isPickable', false, [AbstractControl.namePostfix]);
        Helper.setSceneMesh(scene, 'checkCollisions', false);
        const roaming = new GravityRoaming(scene, {
            floorMeshKey: RawAssetsName.ground,
            obstacleMeshKey: RawAssetsName.bound,
            autoUpdate: true,
            gravity: new Vector3(0, -9.8 / 60, 0),
        });
    }

    private static setModel(stage: DefaultStage): void {
        const scene = stage.mainScene;
        const loader = stage.loader(scene);
        const model = loader.getMeshTaskInfo(RawAssetsUrl.changjing)?.loadedMeshes!;
    }

    private static setFog(stage: DefaultStage): void {
        const scene = stage.mainScene;
        scene.fogEnabled = true;
        scene.fogMode = Scene.FOGMODE_LINEAR;
        scene.fogStart = 1;
        scene.fogEnd = 100;
        scene.fogColor = Color3.FromHexString('#aaaaaa');
    }

    private static testDebug(stage: DefaultStage): void {
        Debug.initialize(stage.mainScene, {
            scattered: true,
            offset: new Vector3(2, 0, 0),
            lockToCamera: true
        });

        // AnimationFrame.request(()=>{
        //     Debug.log('FPS:',stage.engine.performanceMonitor.averageFPS);
        // },1000,1200,{});
    }

    private static testXRDrag(stage: DefaultStage): Drag {
        const s = 1;
        const box = MeshBuilder.CreateBox('box', { width: s, height: s, depth: s }, stage.mainScene);
        box.position.set(0, 1, 0);
        const material = new StandardMaterial('box-material', stage.mainScene);
        material.emissiveColor = new Color3(0, 1, 0);
        box.material = material;


        const drag = new Drag();
        const config = new DragCommonConfig();
        const limit = new DragNoneLimit();
        drag.addTarget(box, config, limit);

        const scene = stage.mainScene;
        const xr = stage.vr!;
        stage.vr?.onEnter((data) => {
        });
        stage.vr?.onIn((data) => {
        });
        stage.vr?.onExit((data) => {
        });
        stage.vr?.onNotIn((data) => {
        });

        // stage.scene.onPointerDown = (e, p, t) => {
        //     const camera = scene.activeCamera!;
        //     const tmp = [];
        //     for (const n of camera.getViewMatrix().m) {
        //         tmp.push(n.toFixed(2));
        //     }
        //     Debug.log('camera:', tmp);
        // };

        return drag;
    }

    private static initializeSky(stage: DefaultStage): GradientSkybox {
        return new GradientSkybox('sky', stage.mainScene, {
            values: [0, 0.6, 0.8],
            colors: ['#000000', '#00375c', '#52baff'],
            size: 500,
        });
    }

}

export { GenerateComponent };
